﻿/**
 * Reflection
 *
 * @author		Duarte Peixinho
 * @version		1.0
 */


package com.duartepeixinho.reflection 
{

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.display.DisplayObject;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	
	
	public class Reflection extends Sprite
	{
		
		private var _reflectedImage:Bitmap = new Bitmap();
		private var _maskCreated:Boolean = false;
		private var _maskShape:Shape;
		private var _bitmapdata:BitmapData;
		private var _bitmapdataObject:BitmapData;
		private var _alpha:Number;

		/**
		 * Constructor
		 */
		public function Reflection() {
			
		}
		
		/**
		 * CreateReflection
		 * @param	object				DisplayObject		Object to be reflected
		 * @param	width				Number				Reflection Width
		 * @param	height				Number				Reflection Height
		 * @param	ratios				Array				Ratios of the Reflection, eg: [0, 63, 127, 190, 255]
		 * @param	alpha				Number				Alpha value
		 * @param	backgroundColor		uint				Background Color
		 * @param	filters				Array				Filters Array
		 */
		public function createReflection(object:DisplayObject, width:Number, height:Number, ratios:Array, alpha : Number = 1, backgroundColor:uint = 0xffffff, filters:Array = null, dynamicBorders:Boolean = true):void {
			_alpha = alpha;

			//cleaning childs and disposing bitmapdata to avoid memory leak
			if (numChildren > 0) {
				removeChildAt(0);
				_bitmapdata.dispose();
				_bitmapdataObject.dispose();
			}
			
			//getting clip bounds
			var _bounds:Rectangle;
			if (dynamicBorders) _bounds = object.getBounds(object);
			else _bounds = new Rectangle(0, 0, width, height);
			
			//converting object to image
			_bitmapdata = new BitmapData(width,height,true,backgroundColor);
			
			//creating matrix to rotate image reflection
			var matrix:Matrix = new Matrix();
			matrix.scale( -1, 1);
			matrix.rotate(Math.PI);
			matrix.translate(0, height);
			
			//applying matrix transformations
			_bitmapdataObject = new BitmapData(width, height, true, backgroundColor);
			_bitmapdataObject.draw(object,new Matrix(1,0,0,1,-_bounds.x-1,-_bounds.y));
			_bitmapdata.draw(_bitmapdataObject, matrix);
			
			//creating mask
			if (!_maskCreated) {
				_maskShape = createMask(width, height,ratios);	
				_maskShape.cacheAsBitmap = true;
				addChild(_maskShape);
			}
			
			//converting to image
			_reflectedImage = new Bitmap(_bitmapdata,"auto",true);

			//applying mask
			_reflectedImage.cacheAsBitmap = true;
			_reflectedImage.mask = _maskShape;
			
			//applying filters
			if (filters && _reflectedImage.filters.length==0) 
			_reflectedImage.filters = filters;
			
			//adding child to sprite
			addChildAt(_reflectedImage, 0);				

		}

		/**
		 * 
		 * @param	sizeX		uint		Width
		 * @param	sizeY		uint		Height
		 * @param	ratios		Array		Ratio of the reflection
		 * @return				Shape		Returns the mask to be applied to the sprite, creating a reflection with a fade effect
		 */
		private function createMask(sizeX:uint, sizeY:uint, ratios:Array):Shape {
			_maskCreated = true;
			var shape:Shape = new Shape();
			var matrix:Matrix = new Matrix();
			
			matrix.rotate( -Math.PI / 2);
			matrix.createGradientBox(sizeX, sizeY,(Math.PI / 2));
			
			var fillType:String = "linear";
			var colors:Array = [0x000000, 0x000000];
			var alphas:Array = [1, 0];
			
			if (ratios.length==0) ratios = [0, 127];
			shape.x -= 1;
			shape.graphics.beginGradientFill(fillType,colors,alphas,ratios,matrix);
			shape.graphics.drawRect(0, 0, sizeX+1, sizeY+1);
			shape.graphics.endFill();
			return shape;
		}
		
	}
	
}